package cn.easyplatform.studio.utils;

import cn.easyplatform.lang.Strings;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.stat.TableStat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegularUtils {
    private static Logger log = LoggerFactory.getLogger(RegularUtils.class);
    private enum RegularType {
        //相等，SQL语句，逻辑语句，前端事件语句, 前端逻辑语句
        RegularEqual, RegularSQL, RegularLogic, RegularEvent, RegularPageLogic
    }
    //逻辑匹配类型
    private enum LogicType {
        //一个参数参数类型为相等，一个参数参数类型为sql，
        // 两个参数第一个为不匹配第二个为sql,两个参数第一个相等第二个表达式,
        // 两个参数第一个为SQL第二个为表达式,两个参数第一个为不匹配第二个相等,两个参数第一个为相等第二个不匹配
        // 两个参数第一个相等第二个为多个字符参数,一个参数
        //一个参数参数类型为表达式
        LogicOneParamEqual, LogicOneParamSQL, LogicTwoParamNoneSQL, LogicTwoParamEqualExpr,
        LogicTwoParamSQLExpr, LogicTwoParamNoneEqual, LogicTwoParamEqualNone,
        LogicTwoParamEqualMore, LogicTwoParamExprMore, LogicThreeParamEqualNumMore,
        LogicOneParamExpr
    }
    //页面标签匹配类型
    private enum LabelType {
        //标签的属性类型为相等，标签的属性类型为sql，标签的属性类型为逻辑表达式，标签的属性类型为页面事件表达式
        LabelTypeEqual, LabelTypeSQL, LabelTypeLogic, LabelTypeEvent
    }
    private static final String chatRegular = "((\\'[^\\']*?\\')|(\\\"[^\\\"]*?\\\"))";
    private static final String exprRegular = "((\\'\\w*?\\')|(\\\"\\w*?\\\")|(\\'[^\\']*[^\\w\\']+[^\\']*\\')|(\\\"[^\\\"]*[^\\w\\\"]+[^\\\"]*\\\"))";
    private static final String boolRegular = "[^\\\"\\']*";
    private static final String numRegular = "\\d+";
    private static final String moreSpaceRegular = "\\s*";

    //语法匹配
    public static List<String> getLogicGrammar(String content) {
        List<String> idList = new ArrayList<>();
        //每个逻辑要取的片段下标
        List<List<Integer>> groupIndex = new ArrayList<>();
        //每个逻辑片段的组长度
        List<Integer> groupNum = new ArrayList<>();
        //每个逻辑要取的片段的类型
        List<List<RegularType>> groupTypeIndex = new ArrayList<>();
        StringBuffer comment = new StringBuffer();

        getLogicRegular(groupIndex, groupNum, groupTypeIndex, comment);

        match(content, comment.toString(), idList, groupIndex, groupNum, groupTypeIndex);
        return idList;
    }

    private static void getLogicRegular(List<List<Integer>> groupIndex, List<Integer> groupNum,
                                        List<List<RegularType>> groupTypeIndex, StringBuffer comment) {
        //#include ""
        comment.append("(#include\\s+").append(chatRegular).append(moreSpaceRegular).append(")+");
        groupNum.add(4);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularEqual));

        //#app.refresh(String id)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#app\\.refresh", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectObject(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "#db\\.selectObject", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectObject(String dsId, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "#db\\.selectObject", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectOne(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "#db\\.selectOne", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectOne(String dsId, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "#db\\.selectOne", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectList(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "#db\\.selectList", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectList(String dsId, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "#db\\.selectList", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectList(String sql, int pageNo, int pageSize,String orderBy)
        comment.append("|");
        comment.append("(#db\\.selectList\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(7);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularSQL));

        //#db.selectList(String dsId, String sql, int pageNo,int pageSize, String orderBy)
        comment.append("|");
        comment.append("(#db\\.selectList\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(10);
        groupIndex.add(addGroupDefaultIndex(5));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularSQL));

        //#db.selectMapping(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "#db\\.selectMapping", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.selectMapping(String dsId,String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "#db\\.selectMapping", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.transfer(String tableId, String expr)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualExpr, "#db\\.transfer", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.transfer(String tableId, String expr, boolean isAutoCommit)
        StringBuffer transferComment = new StringBuffer();
        transferComment.append(moreSpaceRegular).append(boolRegular).append(moreSpaceRegular);
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualExpr, "#db\\.transfer", groupIndex,
                groupNum, groupTypeIndex, comment, null, transferComment.toString());

        //#db.update(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "#db\\.update", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.update(String dsi, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "#db\\.update", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.update(String sql, boolean isAutoCommit)
        StringBuffer dbUpdateComment = new StringBuffer();
        dbUpdateComment.append(moreSpaceRegular).append(boolRegular).append(moreSpaceRegular);
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "#db\\.update", groupIndex,
                groupNum, groupTypeIndex, comment, null, dbUpdateComment.toString());

        //#db.update(String dsId, String sql, boolean isAutoCommit)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "#db\\.update", groupIndex,
                groupNum, groupTypeIndex, comment, null, dbUpdateComment.toString());

        //#db.init(String tableId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#db\\.init", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.getEntity(String id)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#db\\.getEntity", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#db.lock(String tableId, Object... keys)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#db\\.lock", groupIndex,
                groupNum, groupTypeIndex, comment, null, "[^\\)]*?");

        //#db.unlock(String tableId, Object... keys)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#db\\.unlock", groupIndex,
                groupNum, groupTypeIndex, comment, null, "[^\\)]*?");

        //listID.load(String sql, String expr)
        addGroupDefaultRegular(LogicType.LogicTwoParamSQLExpr, "\\.load", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //listID.load(int layer, String taskId, String listId, String expr)
        comment.append("|");
        comment.append("(\\.load\\(").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).append(",").
                append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append(",").
                append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append(",").
                append(moreSpaceRegular).append(exprRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(12);

        List<Integer> indexList = new ArrayList<>();
        indexList.add(2);
        indexList.add(5);
        indexList.add(8);
        groupIndex.add(indexList);

        List<RegularType> typeList = new ArrayList<>();
        typeList.add(RegularType.RegularEqual);
        typeList.add(RegularType.RegularEqual);
        typeList.add(RegularType.RegularLogic);
        groupTypeIndex.add(typeList);

        //listID.load(int layer, String listId, String expr)
        StringBuffer IDLoadComment = new StringBuffer();
        IDLoadComment.append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular);
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualExpr, "\\.load", groupIndex,
                groupNum, groupTypeIndex, comment, IDLoadComment.toString(), null);

        //listID.from$(String listId, String expr)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualExpr, "\\.from\\$", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //listID.from$(String listId, String expr, boolean sel)
        StringBuffer IDFromComment = new StringBuffer();
        IDFromComment.append(moreSpaceRegular).append(boolRegular).append(moreSpaceRegular);
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualExpr, "\\.from\\$", groupIndex,
                groupNum, groupTypeIndex, comment, null, IDFromComment.toString());

        //go(String taskid, String code)
        //addGroupDefaultRegular(LogicType.LogicTwoParamEqualNone, "go", groupIndex,groupNum, groupTypeIndex, comment, null, null);

        //go(String taskid)
        //addGroupDefaultRegular(LogicType.LogicOneParamEqual, "go", groupIndex,groupNum, groupTypeIndex, comment, null, null);

        //go(String taskid, String code, boolean flag)
        //addGroupDefaultRegular(LogicType.LogicTwoParamEqualNone, "go", groupIndex,groupNum, groupTypeIndex, comment, null, IDFromComment.toString());

        //go(String taskid, .....)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "go", groupIndex,
                groupNum, groupTypeIndex, comment, null, ".*");

        //invoke(String expr, String[] args)
        addGroupDefaultRegular(LogicType.LogicTwoParamExprMore, "invoke", groupIndex,
                groupNum, groupTypeIndex, comment, null, IDFromComment.toString());

        //load(String sql)
        comment.append("|");
        comment.append("((([^\\.]{1})|^)load\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(6);
        groupIndex.add(addGroupDefaultIndex(4));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularSQL));

        //load(String sql, String expr)
        comment.append("|");
        comment.append("((([^\\.]{1})|^)load\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(exprRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(11);
        indexList = new ArrayList<>();
        indexList.add(4);
        indexList.add(7);
        groupIndex.add(indexList);
        typeList = new ArrayList<>();
        typeList.add(RegularType.RegularSQL);
        typeList.add(RegularType.RegularLogic);
        groupTypeIndex.add(typeList);

        //load(int layer, String expr)
        comment.append("|");
        comment.append("((([^\\.]{1})|^)load\\(").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(exprRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(8);
        groupIndex.add(addGroupDefaultIndex(4));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularLogic));

        //load(int layer, String taskId, String expr)
        comment.append("|");
        comment.append("((([^\\.]{1})|^)load\\(").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(exprRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(11);
        indexList = new ArrayList<>();
        indexList.add(4);
        indexList.add(7);
        groupIndex.add(indexList);
        typeList = new ArrayList<>();
        typeList.add(RegularType.RegularEqual);
        typeList.add(RegularType.RegularLogic);
        groupTypeIndex.add(typeList);

        //#bpm.getInstanceTask(String processId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.getInstanceTask", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.startAndExecute(String processId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.startAndExecute", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.startAndExecute(String processId, String nodeName)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualNone, "#bpm\\.startAndExecute", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.execute(String taskId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.execute", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.take(String taskId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.take", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.withdraw(String taskId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.withdraw", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.executeAndJumpTask(String taskId, String nodeName)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualNone, "#bpm\\.executeAndJumpTask", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.reject(String taskId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.reject", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.resignTo(String taskId, String... actorIds)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualMore, "#bpm\\.resignTo", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.resignTo(String taskId, int performType, String... actorIds)
        addGroupDefaultRegular(LogicType.LogicThreeParamEqualNumMore, "#bpm\\.resignTo", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.addTaskActor(String taskId, String... actorIds)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualMore, "#bpm\\.addTaskActor", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.addTaskActor(String taskId, int performType, String... actorIds)
        addGroupDefaultRegular(LogicType.LogicThreeParamEqualNumMore, "#bpm\\.addTaskActor", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.removeTaskActor(String taskId, String... actorIds)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualMore, "#bpm\\.removeTaskActor", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.terminate(String orderId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.terminate", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.getNodes(String processId)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "#bpm\\.getNodes", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);

        //#bpm.getNextNodes(String processId, String nodeName, String... params)
        comment.append("|");
        comment.append("(#bpm\\.getNextNodes\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append("(,\\s*(\\'|\\\")[^)]+)*\\s*").append("\\))+");
        groupNum.add(9);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularEqual));

        //#bpm.getActors(String processId, String nodeName)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualNone, "#bpm\\.getActors", groupIndex,
                groupNum, groupTypeIndex, comment, null, null);
    }

    private static List<Integer> addGroupDefaultIndex(Integer index) {
        List<Integer> indexList = new ArrayList<>();
        indexList.add(index);
        return indexList;
    }

    private static List<RegularType> addGroupDefaultType(RegularType type) {
        List<RegularType> indexList = new ArrayList<>();
        indexList.add(type);
        return indexList;
    }

    /**
     * 逻辑语法快速设置表达式
     * @param type              逻辑类型
     * @param logicPrefix       逻辑前缀
     * @param groupIndex        需要数据的组的下标
     * @param groupNum          这个逻辑的组的长度
     * @param groupType         需要数据的组内容的类型
     * @param comment           整个完整的正则表达式
     * @param prefixComment     在这个逻辑的参数类型的参数判断前面增加一个不影响组的正则表达式，除了最后一段，每段表达式要加","
     * @param suffixComment     在这个逻辑的参数类型的参数判断后面增加一个不影响组的正则表达式，除了最后一段，每段表达式要加","
     */
    private static void addGroupDefaultRegular(LogicType type, String logicPrefix, List<List<Integer>> groupIndex,
                                               List<Integer> groupNum, List<List<RegularType>> groupType,
                                               StringBuffer comment, String prefixComment, String suffixComment) {
        if (type == LogicType.LogicOneParamEqual || type == LogicType.LogicOneParamSQL) {
            comment.append("|");
            StringBuffer appComment = new StringBuffer();
            appComment.append("(" + logicPrefix + "\\(");
            if (Strings.isBlank(prefixComment) == false)
                appComment.append(prefixComment).append(",");
            appComment.append(moreSpaceRegular).append(chatRegular).
                    append(moreSpaceRegular);
            if (Strings.isBlank(suffixComment) == false)
                appComment.append(",").append(suffixComment);
            appComment.append("\\))+");
            comment.append(appComment);
            groupNum.add(4);
            groupIndex.add(addGroupDefaultIndex(2));//取第2个
            if (type == LogicType.LogicOneParamEqual)
                groupType.add(addGroupDefaultType(RegularType.RegularEqual));
            else if (type == LogicType.LogicOneParamSQL)
                groupType.add(addGroupDefaultType(RegularType.RegularSQL));
        } else if (type == LogicType.LogicTwoParamNoneSQL || type == LogicType.LogicTwoParamNoneEqual
                || type == LogicType.LogicTwoParamEqualNone) {
            comment.append("|");
            StringBuffer appComment = new StringBuffer();
            appComment.append("("+ logicPrefix + "\\(");
            if (Strings.isBlank(prefixComment) == false)
                appComment.append(prefixComment).append(",");
            appComment.append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append(",").
                    append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular);
            if (Strings.isBlank(suffixComment) == false)
                appComment.append(",").append(suffixComment);
            appComment.append("\\))+");
            comment.append(appComment);
            groupNum.add(7);
            if (type == LogicType.LogicTwoParamEqualNone)
                groupIndex.add(addGroupDefaultIndex(2));//取第2个
            else
                groupIndex.add(addGroupDefaultIndex(5));//取第5个
            if (type == LogicType.LogicTwoParamNoneSQL)
                groupType.add(addGroupDefaultType(RegularType.RegularSQL));
            else if (type == LogicType.LogicTwoParamNoneEqual || type == LogicType.LogicTwoParamEqualNone)
                groupType.add(addGroupDefaultType(RegularType.RegularEqual));
        } else if (type == LogicType.LogicTwoParamEqualExpr || type == LogicType.LogicTwoParamSQLExpr) {
            comment.append("|");
            StringBuffer appComment = new StringBuffer();
            appComment.append("("+ logicPrefix + "\\(");
            if (Strings.isBlank(prefixComment) == false)
                appComment.append(prefixComment).append(",");
            appComment.append(moreSpaceRegular).append(chatRegular).
                    append(moreSpaceRegular).append(",").append(moreSpaceRegular).append(exprRegular).
                    append(moreSpaceRegular);
            if (Strings.isBlank(suffixComment) == false)
                appComment.append(",").append(suffixComment);
            appComment.append("\\))+");
            comment.append(appComment);
            groupNum.add(9);

            List<Integer> indexList = new ArrayList<>();
            indexList.add(2);
            indexList.add(5);
            groupIndex.add(indexList);

            List<RegularType> typeList = new ArrayList<>();
            if (type == LogicType.LogicTwoParamEqualExpr)
                typeList.add(RegularType.RegularEqual);
            else if (type == LogicType.LogicTwoParamSQLExpr)
                typeList.add(RegularType.RegularSQL);
            typeList.add(RegularType.RegularLogic);
            groupType.add(typeList);
        } else if (type == LogicType.LogicTwoParamEqualMore || type == LogicType.LogicThreeParamEqualNumMore ||
                type == LogicType.LogicTwoParamExprMore) {
            comment.append("|");
            comment.append("("+ logicPrefix + "\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular);
            if (type == LogicType.LogicThreeParamEqualNumMore)
                comment.append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular);
            comment.append("(,\\s*(\\'|\\\")[^)]+)*\\s*").append("\\))+");
            groupNum.add(6);
            groupIndex.add(addGroupDefaultIndex(2));//取第2个
            if (type == LogicType.LogicTwoParamExprMore)
                groupType.add(addGroupDefaultType(RegularType.RegularLogic));
            else
                groupType.add(addGroupDefaultType(RegularType.RegularEqual));
        } else if (type == LogicType.LogicOneParamExpr) {
            comment.append("|");
            StringBuffer appComment = new StringBuffer();
            appComment.append("("+ logicPrefix + "\\(");
            if (Strings.isBlank(prefixComment) == false)
                appComment.append(prefixComment).append(",");
            appComment.append(moreSpaceRegular).append(exprRegular).append(moreSpaceRegular);
            if (Strings.isBlank(suffixComment) == false)
                appComment.append(",").append(suffixComment);
            appComment.append("\\))+");
            comment.append(appComment);
            groupNum.add(6);
            groupIndex.add(addGroupDefaultIndex(2));//取第2个
            groupType.add(addGroupDefaultType(RegularType.RegularLogic));
        }
    }

    private static void match(String content, String comment, List<String> idList, List<List<Integer>> groupIndex,
                              List<Integer> groupNum, List<List<RegularType>> groupType) {
        Pattern pattern = Pattern.compile(comment, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);
        List<Integer> groupStart = new ArrayList<>();
        groupStart.add(1);
        for (Integer num : groupNum) {
            groupStart.add(groupStart.get(groupStart.size() - 1) + num);
        }
        while(matcher.find()){
            int count = matcher.groupCount();
            for (int index = 1; index < count; index++) {
                String ret = matcher.group(index);
                if (Strings.isBlank(ret) == false) {
                    log.debug(index + ":" + ret);

                    if (groupStart.contains(index) == true) {
                        //获取每个逻辑片段的组开始的下标，加上需要读取的下标的位置，就是最终数据
                        //最开始组的下标
                        Integer eachGroupIndex = groupStart.indexOf(index);
                        if (groupIndex.size() > eachGroupIndex) {
                            //需要读取的下标
                            List<Integer> lastGroupIndex = groupIndex.get(eachGroupIndex);
                            //需要读取的类型
                            List<RegularType> lastGroupType = groupType.get(eachGroupIndex);
                            for (int i = 0; i < lastGroupIndex.size(); i++) {
                                Integer addIndex = lastGroupIndex.get(i);
                                RegularType addType = lastGroupType.get(i);
                                String result = matcher.group(addIndex + index - 1);
                                //去掉引号
                                result = result.substring(1, result.length() - 1);
                                if (addType == RegularType.RegularEqual) {
                                    if (idList.contains(result) == false)
                                        idList.add(result);
                                } else if (addType == RegularType.RegularSQL) {
                                    List<String> tables = RegularUtils.getSQLGrammar(result);
                                    for (String table : tables) {
                                        if (idList.contains(table) == false)
                                            idList.add(table);
                                    }
                                } else if (addType == RegularType.RegularLogic) {
                                    //如果下标为最终的下标+1或者+2有值，那么内容为相等，
                                    //如果下标为最终的下标+3或者+4有值，那么内容为表达式
                                    if (Strings.isBlank(matcher.group(addIndex + index - 1 + 1)) == false ||
                                            Strings.isBlank(matcher.group(addIndex + index - 1 + 2)) == false) {
                                        if (idList.contains(result) == false)
                                            idList.add(result);
                                    } else if (Strings.isBlank(matcher.group(addIndex + index - 1 + 3)) == false ||
                                            Strings.isBlank(matcher.group(addIndex + index - 1 + 4)) == false) {
                                        //每个逻辑要取的片段下标
                                        List<List<Integer>> newGroupIndex = new ArrayList<>();
                                        //每个逻辑片段的组长度
                                        List<Integer> newGroupNum = new ArrayList<>();
                                        //每个逻辑要取的片段的类型
                                        List<List<RegularType>> newGroupTypeIndex = new ArrayList<>();
                                        StringBuffer newComment = new StringBuffer();
                                        getLogicRegular(newGroupIndex, newGroupNum, newGroupTypeIndex, newComment);
                                        RegularUtils.match(result, newComment.toString(), idList, newGroupIndex,
                                                newGroupNum, newGroupTypeIndex);
                                    }
                                } else if (addType == RegularType.RegularEvent) {
                                    //每个逻辑要取的片段下标
                                    List<List<Integer>> newGroupIndex = new ArrayList<>();
                                    //每个逻辑片段的组长度
                                    List<Integer> newGroupNum = new ArrayList<>();
                                    //每个逻辑要取的片段的类型
                                    List<List<RegularType>> newGroupTypeIndex = new ArrayList<>();
                                    StringBuffer newComment = new StringBuffer();
                                    getLabelRegular(newGroupIndex, newGroupNum, newGroupTypeIndex, newComment);
                                    RegularUtils.match(result, newComment.toString(), idList, newGroupIndex,
                                            newGroupNum, newGroupTypeIndex);
                                } else if (addType == RegularType.RegularPageLogic) {
                                    //每个逻辑要取的片段下标
                                    List<List<Integer>> newGroupIndex = new ArrayList<>();
                                    //每个逻辑片段的组长度
                                    List<Integer> newGroupNum = new ArrayList<>();
                                    //每个逻辑要取的片段的类型
                                    List<List<RegularType>> newGroupTypeIndex = new ArrayList<>();
                                    StringBuffer newComment = new StringBuffer();
                                    getLogicRegular(newGroupIndex, newGroupNum, newGroupTypeIndex, newComment);
                                    RegularUtils.match(result, newComment.toString(), idList, newGroupIndex,
                                            newGroupNum, newGroupTypeIndex);
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
    }

    //SQL匹配
    public static List<String> getSQLGrammar(String content) {
        List<String> idList = new ArrayList<>();
        // 新建 MySQL Parser
        try {
            SQLStatementParser parser = new MySqlStatementParser(content);
            // 使用Parser解析生成AST，这里SQLStatement就是AST
            SQLStatement sqlStatement = parser.parseStatement();
            MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
            sqlStatement.accept(visitor);
            for (TableStat.Name tableName :
                    visitor.getTables().keySet()) {
                String ret = tableName.getName();
                if (idList.contains(ret) == false)
                    idList.add(ret);
            }
        } catch (Exception e) {
            System.out.println("error:"+content);
            e.printStackTrace();
        }

        return idList;
    }

    //标签匹配
    public static List<String> getLabelGrammar(String content) {
        //先查询所有控件的event属性，再重新查询控件的其他属性
        List<String> idList = new ArrayList<>();

        //event属性
        //每个逻辑要取的片段下标
        List<List<Integer>> groupIndex = new ArrayList<>();
        //每个逻辑片段的组长度
        List<Integer> groupNum = new ArrayList<>();
        //每个逻辑要取的片段的类型
        List<List<RegularType>> groupTypeIndex = new ArrayList<>();
        StringBuffer comment = new StringBuffer();

        //<* event
        comment.append("(<\\w+.*\\s+").append("event").append(moreSpaceRegular).append("=").
                append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append(".*?>)+");
        groupNum.add(4);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularEvent));
        match(content, comment.toString(), idList, groupIndex, groupNum, groupTypeIndex);

        //其他属性
        //每个逻辑要取的片段下标
        groupIndex = new ArrayList<>();
        //每个逻辑片段的组长度
        groupNum = new ArrayList<>();
        //每个逻辑要取的片段的类型
        groupTypeIndex = new ArrayList<>();
        comment = new StringBuffer();

        //entity
        addGroupDefaultLabelRegular("entity", LabelType.LabelTypeEqual, groupIndex, groupNum,
                groupTypeIndex, comment);

        //pageId
        comment.append("|");
        addGroupDefaultLabelRegular("pageId", LabelType.LabelTypeEqual, groupIndex, groupNum,
                groupTypeIndex, comment);

        //init
        comment.append("|");
        addGroupDefaultLabelRegular("init", LabelType.LabelTypeLogic, groupIndex, groupNum,
                groupTypeIndex, comment);

        //before
        comment.append("|");
        addGroupDefaultLabelRegular("before", LabelType.LabelTypeLogic, groupIndex, groupNum,
                groupTypeIndex, comment);

        //after
        comment.append("|");
        addGroupDefaultLabelRegular("after", LabelType.LabelTypeLogic, groupIndex, groupNum,
                groupTypeIndex, comment);

        //dbId
        comment.append("|");
        addGroupDefaultLabelRegular("dbId", LabelType.LabelTypeEqual, groupIndex, groupNum,
                groupTypeIndex, comment);

        //query
        comment.append("|");
        addGroupDefaultLabelRegular("query", LabelType.LabelTypeSQL, groupIndex, groupNum,
                groupTypeIndex, comment);

        //condition
        comment.append("|");
        addGroupDefaultLabelRegular("condition", LabelType.LabelTypeSQL, groupIndex, groupNum,
                groupTypeIndex, comment);

        //logic
        comment.append("|");
        addGroupDefaultLabelRegular("logic", LabelType.LabelTypeLogic, groupIndex, groupNum,
                groupTypeIndex, comment);

        //orderId
        comment.append("|");
        addGroupDefaultLabelRegular("orderId", LabelType.LabelTypeEqual, groupIndex, groupNum,
                groupTypeIndex, comment);

        //processId
        comment.append("|");
        addGroupDefaultLabelRegular("processId", LabelType.LabelTypeEqual, groupIndex, groupNum,
                groupTypeIndex, comment);

        //onSave
        comment.append("|");
        addGroupDefaultLabelRegular("onSave", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //onNode
        comment.append("|");
        addGroupDefaultLabelRegular("onNode", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //taskEvent
        comment.append("|");
        addGroupDefaultLabelRegular("taskEvent", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //assigneeEvent
        comment.append("|");
        addGroupDefaultLabelRegular("assigneeEvent", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //assigneeTypeEvent
        comment.append("|");
        addGroupDefaultLabelRegular("assigneeTypeEvent", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //assigneeRoleEvent
        comment.append("|");
        addGroupDefaultLabelRegular("assigneeRoleEvent", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //decisionEvent
        comment.append("|");
        addGroupDefaultLabelRegular("decisionEvent", LabelType.LabelTypeEvent, groupIndex, groupNum,
                groupTypeIndex, comment);

        //autoCreateExpression
        comment.append("|");
        addGroupDefaultLabelRegular("autoCreateExpression", LabelType.LabelTypeLogic, groupIndex, groupNum,
                groupTypeIndex, comment);

        //expSql
        comment.append("|");
        addGroupDefaultLabelRegular("expSql", LabelType.LabelTypeSQL, groupIndex, groupNum,
                groupTypeIndex, comment);

        //taskSql
        comment.append("|");
        addGroupDefaultLabelRegular("taskSql", LabelType.LabelTypeSQL, groupIndex, groupNum,
                groupTypeIndex, comment);

        //<include src
        comment.append("|");
        comment.append("(<include.*\\s+").append("src").append(moreSpaceRegular).append("=").
                append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append(".*?>)+");
        groupNum.add(4);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularEqual));
        match(content, comment.toString(), idList, groupIndex, groupNum, groupTypeIndex);

        match(content, comment.toString(), idList, groupIndex, groupNum, groupTypeIndex);
        return idList;
    }

    //标签event语法
    private static void getLabelRegular(List<List<Integer>> groupIndex, List<Integer> groupNum,
                                        List<List<RegularType>> groupTypeIndex, StringBuffer comment) {
        //selectObject(String sql)
        StringBuffer appComment = new StringBuffer();
        appComment.append("(selectObject\\(").append(moreSpaceRegular).append(chatRegular).
                append(moreSpaceRegular).append("\\))+");
        comment.append(appComment);
        groupNum.add(4);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularSQL));

        //selectObject(String dsId, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "selectObject", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //selectOne(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "selectOne", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //selectOne(String dsId, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "selectOne", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //selectList(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "selectList", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //selectList(String dsId, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "selectList", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //selectList(String sql, int pageNo, int pageSize,String orderBy)
        comment.append("|");
        comment.append("(selectList\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(7);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularSQL));

        //selectList(String dsId, String sql, int pageNo,int pageSize, String orderBy)
        comment.append("|");
        comment.append("(selectList\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(10);
        groupIndex.add(addGroupDefaultIndex(5));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularSQL));

        //executeUpdate(String sql)
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "executeUpdate", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //executeUpdate(String dsi, String sql)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "executeUpdate", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //executeUpdate(String sql, boolean isAutoCommit)
        StringBuffer executeUpdateComment = new StringBuffer();
        executeUpdateComment.append(moreSpaceRegular).append(boolRegular).append(moreSpaceRegular);
        addGroupDefaultRegular(LogicType.LogicOneParamSQL, "executeUpdate", groupIndex, groupNum,
                groupTypeIndex, comment, null, executeUpdateComment.toString());

        //executeUpdate(String dsId, String sql, boolean isAutoCommit)
        addGroupDefaultRegular(LogicType.LogicTwoParamNoneSQL, "executeUpdate", groupIndex, groupNum,
                groupTypeIndex, comment, null, executeUpdateComment.toString());

        //evalList(String listid, String expr)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualExpr, "evalList", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //evalList(String listid, String listid, String expr)
        comment.append("|");
        comment.append("(evalList\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(exprRegular).append(moreSpaceRegular).
                append("\\))+");
        groupNum.add(12);
        List<Integer> indexList = new ArrayList<>();
        indexList.add(2);
        indexList.add(5);
        indexList.add(8);
        groupIndex.add(indexList);

        List<RegularType> typeList = new ArrayList<>();
        typeList.add(RegularType.RegularEqual);
        typeList.add(RegularType.RegularEqual);
        typeList.add(RegularType.RegularLogic);
        groupTypeIndex.add(typeList);

        //evalLogic(String expr)
        addGroupDefaultRegular(LogicType.LogicOneParamExpr, "evalLogic", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        //evalExpr(String expr)
        addGroupDefaultRegular(LogicType.LogicOneParamExpr, "evalExpr", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);

        /*//go(String tasked)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "go", groupIndex, groupNum, groupTypeIndex, comment, null, null);

        //go(String taskid, String code)
        addGroupDefaultRegular(LogicType.LogicTwoParamEqualNone, "go", groupIndex, groupNum, groupTypeIndex, comment, null, null);

        //go(String taskid, int openmodel)
        StringBuffer goComment = new StringBuffer();
        goComment.append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular);
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "go", groupIndex, groupNum, groupTypeIndex, comment, null, goComment.toString());

        //go(String taskid,int openmodel,String code|cid)
        comment.append("|");
        comment.append("(go\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(7);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularEqual));

        //go(String taskid,int openmodel,String code|cid,String code)
        comment.append("|");
        comment.append("(go\\(").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(numRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).
                append(",").append(moreSpaceRegular).append(chatRegular).append(moreSpaceRegular).append("\\))+");
        groupNum.add(10);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        groupTypeIndex.add(addGroupDefaultType(RegularType.RegularEqual));*/
        //go(String taskid, .....)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "go", groupIndex,
                groupNum, groupTypeIndex, comment, null, ".*");

        //setTask(String taskid)
        addGroupDefaultRegular(LogicType.LogicOneParamEqual, "setTask", groupIndex, groupNum,
                groupTypeIndex, comment, null, null);
    }

    /**
     * 标签匹配语法
     * @param logicPrefix           逻辑片段前缀
     * @param type                  标签逻辑类型
     * @param groupIndex            需要获取数据的组的下标
     * @param groupNum              逻辑组的总数
     * @param groupType             需要获取数据的组的类型
     * @param comment               正则表达式
     */
    private static void addGroupDefaultLabelRegular(String logicPrefix, LabelType type,
                                                    List<List<Integer>> groupIndex, List<Integer> groupNum,
                                                    List<List<RegularType>> groupType, StringBuffer comment) {
        StringBuffer appComment = new StringBuffer();
        appComment.append("(\\s+" + logicPrefix).append(moreSpaceRegular).append("=").append(moreSpaceRegular).
                append(chatRegular).append(")+");
        comment.append(appComment);
        groupNum.add(4);
        groupIndex.add(addGroupDefaultIndex(2));//取第2个
        if (type == LabelType.LabelTypeEqual)
            groupType.add(addGroupDefaultType(RegularType.RegularEqual));
        else if (type == LabelType.LabelTypeSQL)
            groupType.add(addGroupDefaultType(RegularType.RegularSQL));
        else if (type == LabelType.LabelTypeLogic)
            groupType.add(addGroupDefaultType(RegularType.RegularPageLogic));
        else if (type == LabelType.LabelTypeEvent)
            groupType.add(addGroupDefaultType(RegularType.RegularEvent));
    }
}
